package de.justphil.tcg.tcgserver.game.mechanics.property.properties;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.List;

import de.justphil.tcg.tcgserver.commons.exceptions.TCGException;
import de.justphil.tcg.tcgserver.game.mechanics.event.Event;
import de.justphil.tcg.tcgserver.game.mechanics.game.Attack;
import de.justphil.tcg.tcgserver.game.mechanics.game.Game;
import de.justphil.tcg.tcgserver.game.mechanics.monster.Monster;
import de.justphil.tcg.tcgserver.game.mechanics.monster.MonsterList;
import de.justphil.tcg.tcgserver.game.mechanics.property.Property;

public class MultiAttack extends Property {

	private boolean attacking;

	public MultiAttack(Game game) {

		super(game);
		attacking = false;
	}
	
	@Override
	public int getType() {

		return PROPERTY_MULTI_ATTACK;
	}

	@Override
	protected List<Integer> getListeningEventTypes() {

		List<Integer> types = super.getListeningEventTypes();
		types.add(Event.EVENT_ATTACK_INVOKED);

		return types;
	}

	@Override
	protected MonsterList handleEvent(Event event) {

		int eventType = event.getType();

		switch (eventType) {
		case Event.EVENT_ATTACK_INVOKED:

			handleAttackInvoked((Attack) event.getData());
			break;
		case Event.EVENT_ATTACK_FINISHED:

			handleAttackFinished((Attack) event.getData());
			break;

		default:
			assert false;
			break;
		}
		return null;
	}

	private void handleAttackInvoked(Attack attack) {

		Monster monster = getMonster();

		if (attack.getAttacker().equals(monster) && !attacking) {

			attacking = true;

			MonsterList enemies = getBoardInfo().getEnemies(monster);
			enemies.remove(attack.getTarget());

			for (Monster enemy : enemies) {

				Attack neighbourAttack = new Attack(monster, enemy);
				try {

					getScheduler().scheduleFirst(
							new Event(Event.EVENT_ATTACK_INVOKED,
									neighbourAttack), 0.0);

					getScheduler()
							.scheduleLast(
									new Event(Event.EVENT_ATTACK,
											neighbourAttack), 0.0);

					getScheduler().scheduleLast(
							new Event(Event.EVENT_ATTACK_FINISHED,
									neighbourAttack), 0.0);

				} catch (TCGException e) {

					assert false: e.getMessage();
				}
			}
		}
	}

	private void handleAttackFinished(Attack attack) {

		Monster monster = getMonster();

		if (attack.getAttacker().equals(monster)) {

			attacking = false;
		}
	}
	
	@Override
	public void writeData(Game game, DataOutput out) throws IOException {

		super.writeData(game, out);
		
		out.writeBoolean(attacking);
	}
	
	@Override
	public void readData(Game game, DataInput in) throws IOException {

		super.readData(game, in);
		
		attacking = in.readBoolean();
	}
}
